package eteam.aps.systemservice.bll;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;
import eteam.aps.common.exceptions.AuthException;
import eteam.aps.common.helper.Helper;
import eteam.aps.common.helper.JwtUtils;
import eteam.aps.systeminterface.model.dto.*;
import eteam.aps.systeminterface.model.entity.*;
import eteam.aps.systemservice.dal.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 系统相关业务
 */
@Service
public class SystemBll {
    @Autowired
    public OnlineUserDal onlineUserDal;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private UserDal userDal;
    @Autowired
    private ModuleDal moduleDal;
    @Autowired
    private ModuleoperDal moduleoperDal;
    @Autowired
    private FunaclDal funaclDal;
    @Autowired
    private FlowBillDal flowBillDal;
    @Autowired
    private FlowBillPropertyDal flowBillPropertyDal;
    @Autowired
    private StartInfoDal startInfoDal;

    /**
     * 构建Token
     *
     * @param username: 用户名
     * @param password: 密码
     * @return: 用户Token信息
     */
    public UserEntity BuildToken(String username, String password) throws Exception {
        UserEntity tmpUser = userDal.getUserByUsername(username);
        if (Helper.checkObjAllFieldsIsNull(tmpUser)) {
            throw new Exception("用户不存在");
        }
        if (!tmpUser.getFpassword().equals(password)) {
            throw new Exception("密码不正确");
        }
        tmpUser.setFpassword(null);
        OnlineUserEntity tmpOnline = new OnlineUserEntity();
        tmpOnline.setFtoken(Helper.GetId());
        tmpOnline.setFuserid(tmpUser.getFuserid());
        tmpOnline.setFclienttype("web");
        tmpOnline.setFclientip(ServletUtil.getClientIP(request));
        tmpOnline.setFlogintime(DateUtil.date());
        tmpOnline.setFlastaccesstime(DateUtil.date());
        //构建TokenInfo
        VerifyTokenDto tokenDto = new VerifyTokenDto();
        tokenDto.setFuserid(tmpUser.getFuserid());
        tokenDto.setFusername(tmpUser.getFusername());
        tokenDto.setFfullname(tmpUser.getFfullname());
        tokenDto.setFpersonid(tmpUser.getFpersonid());
        tokenDto.setFgrouporgid(tmpUser.getFgrouporgid());
        tokenDto.setFisdealer(tmpOnline.getFisdealer());
        tokenDto.setFclienttype(tmpOnline.getFclienttype());
        //生成Token
        //String jsonStr = JSONUtil.toJsonPrettyStr(tokenDto);
        //JSONObject jsonObject = JSONUtil.parseObj(jsonStr);
        //VerifyTokenDto a = JSONUtil.toBean(jsonStr, VerifyTokenDto.class);
        String retToken = JwtUtils.buildToken(tmpUser.getFuserid(), JSONUtil.toJsonStr(tokenDto), tmpOnline.getFclienttype(), 0);
        //Map<String, Claim> userData = JwtUtils.verifyToken(retToken);
        //String userData = JwtUtils.verifyTokenRetJson(retToken);
        //记录Token
        tmpOnline.setFtokeninfo(retToken);
        tmpUser.setFtoken(retToken);

        onlineUserDal.deleteTokenByUserId(tmpUser.getFuserid());
        onlineUserDal.insertOnlineUser(tmpOnline);

        List<UserEntity> roleList = userDal.getGroupByUserId(tmpUser.getFuserid());
        tmpUser.setRoles(roleList.stream().map(UserEntity::getFusername).collect(Collectors.toList()));
        tmpUser.setUsecases(funaclDal.getOperationsByUserId(tmpUser.getFuserid()));
        Map<String,String> res = userDal.getUserDeptAndCode(tmpUser.getFuserid(),tmpUser.getFgrouporgid());
        tmpUser.setEmpcode(res.get("empcode"));
        tmpUser.setDeptcode(res.get("deptcode"));
        return tmpUser;
    }

    /**
     * 获取当前登录账号模块树形列表【只支持2级菜单】
     *
     * @param tokenDto: 当前登录信息
     * @throws Exception
     * @throws AuthException
     * @return: 返回模块列表
     */
    public List<ModuleEntity> getModuleListByTokenInfo(VerifyTokenDto tokenDto) throws Exception, AuthException {
        if (Helper.checkObjAllFieldsIsNull(tokenDto)) {
            throw new AuthException("Token无效");
        }
        List<ModuleEntity> tmpList = moduleDal.getWebModulesByUserId(tokenDto.getFuserid());
        List<ModuleEntity> rootList = tmpList.stream()
                .filter(p -> StrUtil.isEmpty(p.getFparentid()))
                .sorted(Comparator.comparing(ModuleEntity::getSort))
                .collect(Collectors.toList());
        rootList.forEach(p -> p.setChildren(tmpList.stream()
                .filter(q -> p.getFmoduleid().equals(q.getFparentid()))
                .sorted(Comparator.comparing(ModuleEntity::getSort))
                .collect(Collectors.toList())));
        return rootList;
    }

    /**
     * 获取所有模块树形列表【支持多级菜单】
     *
     * @throws Exception
     * @throws AuthException
     * @return: 返回模块树形列表
     */
    public List<ModuleEntity> getModuleList() throws Exception, AuthException {
        List<ModuleEntity> tmpAllList = moduleDal.getWebModules();
        List<ModuleEntity> rootList = tmpAllList.stream()
                .filter(p -> StrUtil.isEmpty(p.getFparentid()))
                .sorted(Comparator.comparing(ModuleEntity::getSort))
                .collect(Collectors.toList());
        rootList.forEach(p -> setChildren(p, tmpAllList));
        return rootList;
    }

    private void setChildren(ModuleEntity module, List<ModuleEntity> list) {
        List<ModuleEntity> tmpList = list.stream().filter(q -> module.getFmoduleid().equals(q.getFparentid())).sorted(Comparator.comparing(ModuleEntity::getSort)).collect(Collectors.toList());
        module.setChildren(tmpList);
        module.setUclist(moduleoperDal.getListByMId((module.getFmoduleid())));
        for (ModuleEntity item : module.getChildren()) {
            setChildren(item, list);
        }
    }

    /**
     * 校验Token是否合法
     *
     * @param token: 用户Token
     * @throws AuthException
     * @return: 返回用户信息
     */
    public VerifyTokenDto VerifyToken(String token) throws AuthException {
        VerifyTokenDto retDto = new VerifyTokenDto();
        try {
            if (StrUtil.isEmpty(token)) {
                throw new AuthException("Token为空");
            }
            OnlineUserEntity tmpOnline = onlineUserDal.getOnlineUserByToken(token);
            if (Helper.checkObjAllFieldsIsNull(tmpOnline)) {
                throw new AuthException("Token无效");
            }
            UserEntity tmpUser = userDal.getUserById(tmpOnline.getFuserid());
            if (Helper.checkObjAllFieldsIsNull(tmpUser)) {
                throw new AuthException("用户不存在");
            }
            retDto.setFuserid(tmpUser.getFuserid());
            retDto.setFusername(tmpUser.getFusername());
            retDto.setFfullname(tmpUser.getFfullname());
            retDto.setFpersonid(tmpUser.getFpersonid());
            retDto.setFgrouporgid(tmpUser.getFgrouporgid());
            retDto.setFisdealer(tmpOnline.getFisdealer());
            retDto.setFclienttype(tmpOnline.getFclienttype());
            return retDto;
        } catch (Exception ex) {
            throw new AuthException(ex.getMessage());
        }
    }

    /**
     * 获取当前账号模块操作列表
     *
     * @throws Exception
     * @return: 权限Key列表
     */
    public List<String> getOperations() throws Exception {
        VerifyTokenDto tokenDto = Convert.convert(VerifyTokenDto.class, request.getAttribute("tokenInfo"));
        return funaclDal.getOperationsByUserId(tokenDto.getFuserid());
    }

    /**
     * 获取已经设置【请求URL】的模块操作列表，此功能对应接口地址
     *
     * @throws Exception
     * @return: 模块操作列表
     */
    public List<ModuleoperDto> getModuleopers() throws Exception, AuthException {
        return moduleoperDal.getModuleopers();
    }


    /**
     * 获取所有单据信息
     *
     * @return 单据信息
     */
    public List<FlowBillClassDto> getAllBillInfoList() {
        List<FlowBillClassDto> flowBillClassDtos = new ArrayList<>();
        //获取所有流程单据entity类
        List<FlowBillEntity> flowBillEntities = flowBillDal.getAllFlowBill();
        //判空
        if (flowBillEntities == null) {
            return null;
        }
        for (FlowBillEntity flowBillEntity : flowBillEntities) {
            FlowBillClassDto flowBillClassDto = new FlowBillClassDto();
            //1、将entity类的数据赋值到Dto类上
            flowBillClassDto.setFWorksheetCode(flowBillEntity.getFWorksheetCode());
            flowBillClassDto.setFWorksheetName(flowBillEntity.getFWorksheetName());
            flowBillClassDto.setFSystemId(flowBillEntity.getFSystemId());

            //2、开始进行流程单据属性赋值
            //根据流程单据Id获取流程属性entity类
            List<FlowBillPropertyEntity> propertyEntities = flowBillPropertyDal.getPropertyByFlowBillId(flowBillEntity.getFSystemId(), flowBillEntity.getFWorksheetName());
            //判空
            if (propertyEntities == null) {
                flowBillClassDto.setCanuseproperties(null);
            }
            //创建Dto列表,将流程属性赋值到Dto列表中
            List<FlowBillPropertyDto> propertyDtos = new ArrayList<>();
            for (FlowBillPropertyEntity propertyEntity : propertyEntities) {
                FlowBillPropertyDto flowBillPropertyDto = new FlowBillPropertyDto();
                flowBillPropertyDto.setPropertyname(propertyEntity.getFDisplayName());
                flowBillPropertyDto.setPropertyvalue(propertyEntity.getFPropName());
                flowBillPropertyDto.setDataType(propertyEntity.getFDataType());
                propertyDtos.add(flowBillPropertyDto);
            }
            //将流程单据属性Dto列表赋值到流程单据Dto中
            flowBillClassDto.setCanuseproperties(propertyDtos);

            //3、开始进行StartInfoDto赋值
            //根据流程单据Id获取地址信息StartInfo实体类
            StartInfoEntity startInfoEntity = startInfoDal.getStartInfoByFlowBillId(flowBillEntity.getFId());
            //判空
            if (startInfoEntity == null) {
                flowBillClassDto.setStartInfo(null);
            } else {
                //开始赋值
                StartInfoDto startInfoDto = new StartInfoDto();
                startInfoDto.setWebFlag(startInfoEntity.getFWebFlag());
                startInfoDto.setWebEditFlag(startInfoEntity.getFWebEditFlag());
                startInfoDto.setAuditFlag(startInfoEntity.getFAuditFlag());
                startInfoDto.setClientFlag(startInfoEntity.getFClientFlag());
                startInfoDto.setMobileFlag(startInfoEntity.getFMobileFlag());
                flowBillClassDto.setStartInfo(startInfoDto);
            }
            //4、完成了一个Dto的信息,添加到需要返回的链表中
            flowBillClassDtos.add(flowBillClassDto);
        }
        return flowBillClassDtos;
    }
}
